package com.cyj.dream.middleware.hystrix.value.impl;

import com.alibaba.fastjson.JSON;
import com.cyj.dream.middleware.hystrix.annotation.DoHystrix;
import com.cyj.dream.middleware.hystrix.value.IValveService;
import com.netflix.hystrix.*;
import org.aspectj.lang.ProceedingJoinPoint;

import java.lang.reflect.Method;

/**
 * @Description: 熔断服务包装--HystrixValveImpl 主要是对 Hystrix 熔断保护的封装，通过继承 HystrixCommand 构造函数中配置启动参数
 * @BelongsProject: DreamChardonnayCloud
 * @BelongsPackage: com.cyj.dream.middleware.hystrix.annotation
 * @Author: ChenYongJia
 * @CreateTime: 2021-09-15 20:17
 * @Email: chen87647213@163.com
 * @Version: 1.0
 */
public class HystrixValveImpl extends HystrixCommand<Object> implements IValveService {

    private ProceedingJoinPoint jp;
    private Method method;
    private DoHystrix doHystrix;

    /**
     * 当熔断时间大于线程休眠时间时，会直接熔断，Setter二次设置熔断时间失效。
     * 解决方案：
     * 通过HystrixValveImpl有参构造（int类型）传递熔断时间。
     *
     * @param time 设置时间
     * @return
     * @date 2021/9/15 20:43
     * @author ChenYongJia
     * @version 1.0
     */
    public HystrixValveImpl(int time) {

        /*********************************************************************************************
         * 置HystrixCommand的属性
         * GroupKey：            该命令属于哪一个组，可以帮助我们更好的组织命令。
         * CommandKey：          该命令的名称
         * ThreadPoolKey：       该命令所属线程池的名称，同样配置的命令会共享同一线程池，若不配置，会默认使用GroupKey作为线程池名称。
         * CommandProperties：   该命令的一些设置，包括断路器的配置，隔离策略，降级设置，以及一些监控指标等。
         * ThreadPoolProperties：关于线程池的配置，包括线程池大小，排队队列的大小等
         *********************************************************************************************/

        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GovernGroup"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("GovernKey"))
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GovernThreadPool"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionTimeoutInMilliseconds(time)
                        .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))
                .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties
                        .Setter().withCoreSize(10)));
    }

    @Override
    public Object access(ProceedingJoinPoint jp, Method method, DoHystrix doHystrix, Object[] args) {
        this.jp = jp;
        this.method = method;
        this.doHystrix = doHystrix;

        // 设置熔断超时时间--在切面接口方法调用中，设置超时熔断时间，withExecutionTimeoutInMilliseconds(doHystrix.timeoutValue())
        // 这个时间信息就是自定义注解中的配置信息
        Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GovernGroup"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionTimeoutInMilliseconds(doHystrix.timeoutValue()));

        return this.execute();
    }

    /**
     * 抽象方法 run()--返回正确方法调用结果
     *
     * @return java.lang.Object
     * @date 2021/9/15 20:24
     * @author ChenYongJia
     * @version 1.0
     */
    @Override
    protected Object run() throws Exception {
        try {
            return jp.proceed();
        } catch (Throwable throwable) {
            return null;
        }
    }

    /**
     * 重写的方法 getFallback()--熔断保护时候返回的对象信息。
     *
     * @return java.lang.Object
     * @date 2021/9/15 20:25
     * @author ChenYongJia
     * @version 1.0
     */
    @Override
    protected Object getFallback() {
        return JSON.parseObject(doHystrix.returnJson(), method.getReturnType());
    }

}
